import gtk
import hildon
from basewindow import BaseWindow
from thread import allocate_lock

class TaskMonitor(BaseWindow):
    def __init__(self, program, widgets):
        """
        Constructor. Creates a new TaskMonitor instance.
        @type program: hildon.Program
        @param program: The Hildon program instance.
        @type widgets: gtk.glade.XML
        @param widgets: A reference to the widget tree of the main ui.
        """
        BaseWindow.__init__(self, program, widgets, 'TaskWindow', 'Task:Vbox', 'Task:Menubar')
        
        # Get references to the needed widgets.
        self.label_widget = widgets.get_widget('Task:StatusLabel')
        self.tree_view = widgets.get_widget('Task:TaskList')

        # Set local member vars.
        self.__taskid = 0
        self.__lock = allocate_lock()
        self.active_tasks = 0
        
        # Attach menu item callbacks.
        quit_menuitem = widgets.get_widget('Task:QuitMenuitem')
        quit_menuitem.connect('activate', gtk.main_quit)

        # Connect button callbacks.
        back_button = widgets.get_widget('Task:BackButton')
        back_button.connect('clicked', self.back_button_clicked)
        clear_button = widgets.get_widget('Task:ClearButton')
        clear_button.connect('clicked', self.clear_button_clicked)

        # Build the needed things for the tree view.
        self.tree_view.set_headers_visible(True)
        self.__add_text_column("Task id", 0)
        self.__add_text_column("Status", 1)
        self.__add_text_column("Message", 2)
        self.__add_progress_column("Progress", 3)
        self.list_store = gtk.ListStore(str, str, str, int) #FIXME
        self.tree_view.set_model(self.list_store)

        # Set the initial mode of the window.
        self.__set_windowed_mode()

    def add_task(self):
        self.__lock.acquire()
        # Check whether the status image must be changed in the browser window.
        if self.active_tasks == 0:
            self.program.image_browser.set_status_image('active')
        self.active_tasks += 1
        self.list_store.append((str(self.__taskid), "Active", "Initializing...", 0))
        tmp = self.__taskid
        self.__taskid += 1
        self.__lock.release()
        return tmp

    def update_task(self, taskid, message, percentage):
        self.__lock.acquire()
        self.list_store.foreach(self.__update_helper, (str(taskid), message, percentage))
        self.__lock.release()
        
    def __update_helper(self, model, path, iter, args):
        (taskid, message, percentage) = args
        if self.list_store.get_value(iter, 0) == taskid:
            self.list_store.set_value(iter, 2, message)
            self.list_store.set_value(iter, 3, percentage)
            return True
        return False

    def remove_task(self, taskid):
        self.__lock.acquire()
        self.list_store.foreach(self.__remove_helper, str(taskid))
        self.active_tasks -= 1
        # Check whether the status image in the image browser should be changed.
        if self.active_tasks == 0:
            self.program.image_browser.set_status_image('inactive')
        self.__lock.release()

    def __remove_helper(self, model, path, iter, taskid):
        if self.list_store.get_value(iter, 0) == taskid:
            # Mark the task as finished (inactive).
            self.list_store.set_value(iter, 1, "Done")
            #self.list_store.remove(iter)
            return True
        return False
    
    def mark_task_error(self, taskid, message):
        self.__lock.acquire()
        self.list_store.foreach(self.__mark_task_error_helper, (str(taskid), message))
        self.active_tasks -= 1
        self.program.image_browser.set_status_image('error')
        self.__lock.release()
    
    def __mark_task_error_helper(self, model, path, iter, args):
        (taskid, message) = args
        if self.list_store.get_value(iter, 0) == taskid:
            # Mark the task as invalid here!
            self.list_store.set_value(iter, 1, "Error")
            self.list_store.set_value(iter, 2, message)
            return True
        return False
    
    def __add_text_column(self, name, cid):
        column = gtk.TreeViewColumn(name, gtk.CellRendererText(), text=cid)
        column.set_resizable(True)
        column.set_sort_column_id(cid)
        self.tree_view.append_column(column)

    def __add_progress_column(self, name, cid):
        column = gtk.TreeViewColumn(name, gtk.CellRendererProgress(), value=cid)
        column.set_resizable(True)
        column.set_sort_column_id(cid)
        self.tree_view.append_column(column)
        
    def __add_pixbuf_column(self, name, cid):
        column = gtk.TreeViewColumn(name, gtk.CellRendererPixbuf(), pixbuf=cid)
        column.set_resizable(True)
        column.set_sort_column_id(cid)
        self.tree_view.append_column(column)

    def show(self):
        if self.fullscreen != self.program.fullscreen:
            self.toggle_fullscreen()
        self.window.show()

    def hide(self):
        # Store the fullscreen status in the program.
        self.program.fullscreen = self.fullscreen
        self.window.hide()

    def back_button_clicked(self, widget):
        self.program.set_mode('browse')

    def fullscreen_key_clicked(self):
        self.toggle_fullscreen()

    def __set_fullscreen_mode(self):
        self.fullscreen = True
        self.window.fullscreen()
        
    def __set_windowed_mode(self):
        self.fullscreen = False
        self.window.unfullscreen()

    def toggle_fullscreen(self):
        """
        Switches between fullscreen and windowed mode.
        """
        # Toggle between fullscreen and windowed mode.
        if self.fullscreen:
            self.__set_windowed_mode()
        else:
            self.__set_fullscreen_mode()
            
    def clear_button_clicked(self, widget):
        self.__lock.acquire()
        to_be_removed = []
        self.list_store.foreach(self.__clear_helper, to_be_removed)
        for iter in to_be_removed:
            self.list_store.remove(iter)
        self.__lock.release()

    def __clear_helper(self, model, path, iter, to_be_removed):
        if self.list_store.get_value(iter, 1) in ('Done', 'Error'):
            to_be_removed.append(iter)

    